#include <iostream>
#include "front/Lexer.h"
#include "front/Parser.h"
#include "front/Semantic.h"
#include "back/ASTtoIRInterpreter.h"
#include "back/SimpleMIPSGenerator.h"
#include "back/Optimizer.h"
#include "front/ASTTransformer.h"
#include "back/OptimizedMipsGen.h"


int main(int argc, char* argv[]) {
    try{
        Lexer lexer;
        if(argc>1){
            Config::parseCmdArgs(argc, argv);
        }else{
            cout << "please input source file path:"<< endl;
            string line;
            getline(std::cin, line);
            Config::parseStdInArgs(line);
        }

        if(Config::sourceFileName.empty()){
            Error::nextErrorDetail << "source file not specified.";
            Error::internal(Error::Can_Not_Open_File);
        }

        lexer.readSourceFile(Config::sourceFileName);
//            lexer.readSourceFileFromStdIn();
        if(Config::printSource) lexer.printSource();
        lexer.parse();
        if(Config::printTokens) lexer.printTokens();

        ASTNode* ast;
        SymbolTable* symTable;

        Parser parser(lexer);
        ast = parser.parse();
        if(Config::printAST) parser.printAST();


        ASTTransformer astTransformer;
        astTransformer.startTraverse(*ast);

        Semantic checker(lexer, *ast);
        symTable = checker.buildSymbolTable();
        if(Config::printSymbolTable) symTable->print();
        checker.check();


        if(Config::printASTDetail){
            PrintAST printer;
            printer.startTraverse(*ast);
        }

        ASTtoIRInterpreter interpreter(*ast, *symTable);
        IRList* irList = interpreter.eval();
        if(Config::printIR){
            cout<< irList->toString() << endl;
        }

        MIPsIns ins;

        if(Config::levelOneOptimize){
            Optimizer optimizer(irList, symTable);
            optimizer.optimize();
            OptimizedMipsGen optGen(irList, ins, optimizer);
            optGen.transform();
        }else{
            SimpleMIPSGenerator mipsGenerator(irList, ins);
            mipsGenerator.transform();
        }

        if(Config::printASM){
            cout << ins.toString() << endl;
        }

        if(!Config::asmFileName.empty()){
            std::ofstream out(Config::asmFileName.c_str());
            out << ins.toString();
            out.close();
        }

    }catch(CommonError* err){

    }catch(runtime_error* err){
        cout << err->what() << endl;
    }catch(runtime_error err){
        cout << err.what() << endl;
    }
    if(!Error::errorList.empty()){
        if(Config::showAllError){
            Error::printAllErrors();
        }else{
            Error::printFirstError();
        }
        return 1;
    }else{
        return 0;
    }
}
